#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2025-01-31-18:37
# @Author  :
# @File    : window.py
# @Software: PyCharm



import tkinter as tk
from tkinter import Toplevel, filedialog, messagebox, simpledialog
from PIL import Image, ImageTk
import os
# 导入ultralytics的YOLO库
from ultralytics import YOLO

# 训练模型的方法
def train_model():
    # 创建子窗口
    top = Toplevel()
    top.title("训练模型")
    top.geometry("300x200")
    top.resizable(False, False)
    def train_model_pt():
        #     修改为自己的配置文件地址
        model = YOLO("yolo11n.pt")
        #     修改为自己的数据集地址
        results = model.train(
            data='ultralytics/datasets/original-license-plates.yaml',
            epochs=1,  # 训练次数
            imgsz=640,  # 输入的图片的大小
            device=0,  # GPU 数
            project='runs/train',  # 输出路径
        )
    # TODO ->训练方法
    def start_training():
        train_model_pt()
        # 模拟训练过程
        messagebox.showinfo("训练完成", "训练完成！")
        top.destroy()  # 训练完成后关闭子窗口

    # 创建开始训练按钮
    start_button = tk.Button(top, text="开始训练", command=start_training)
    start_button.pack(pady=10)

    # 添加说明文字
    description_label = tk.Label(top, text="模型已训练，训练模型花费时间较长", font=("Arial", 10, "italic"))
    description_label.pack(pady=5)

# 检验模型的方法
def validate_model():
    # 创建子窗口
    top = Toplevel()
    top.title("检验模型")
    top.geometry("300x200")
    top.resizable(False, False)

    # 定义变量来存储选择的文件或文件夹
    selected_file = tk.StringVar()

    # 选择文件夹或文件（图片、视频）
    def select_file_or_folder():
        # 弹出选择框，让用户选择文件夹或文件
        file_type = simpledialog.askstring("选择类型", "请输入选择文件夹还是文件（文件夹/文件）：").lower()

        if file_type == "文件":
            # 选择文件（图片或视频）
            selected = filedialog.askopenfilename(
                title="选择文件",
                filetypes=[("所有文件", "*.*"),
                          ("图片文件", "*.jpg;*.png;*.jpeg"),
                          ("视频文件", "*.mp4;*.avi;*.mkv")]
            )
            if selected:
                selected_file.set(selected)
                print(f"选择的文件: {selected}")
            else:
                messagebox.showerror("错误", "未选择任何文件。")
        elif file_type == "文件夹":
            # 选择文件夹
            selected = filedialog.askdirectory(title="选择文件夹")
            if selected:
                selected_file.set(selected)
                print(f"选择的文件夹: {selected}")
            else:
                messagebox.showerror("错误", "未选择任何文件夹。")
        else:
            messagebox.showerror("错误", "选择类型无效，请输入文件夹或文件。")

    def val_model_pt():
        # 加载模型
        model = YOLO('best.pt')  # 加载自定义的训练模型
        # 对模型进行验证
        metrics = model.val(
            data=r'ultralytics/datasets/original-license-plates.yaml',
            save=True,
            conf=0.5,
            device=0,
            project='runs/predict',  # 输出路径
            iou=0.5,
        )  # 调用val方法进行模型验证，不需要传入参数，数据集和设置已被模型记住

        # 输出不同的性能指标
        print("AP (mAP@0.5:0.95):", metrics.box.map)  # 输出平均精度均值（AP，Average Precision）在IoU阈值从0.5到0.95的范围内的结果
        print("AP@0.5 (mAP@0.5):", metrics.box.map50)  # 输出在IoU=0.5时的平均精度（AP50）
        print("AP@0.75 (mAP@0.75):", metrics.box.map75)  # 输出在IoU=0.75时的平均精度（AP75）
        print("APs per category (mAP@0.5:0.95 per category):", metrics.box.maps)  # 输出每个类别在IoU阈值从0.5到0.95的平均精度的列表

    # TODO -> 开始检验按钮
    def start_validation():
        file = selected_file.get()
        if not file:
            messagebox.showerror("错误", "请先选择文件或文件夹。")
            return
        val_model_pt()
        # 模拟检验过程
        messagebox.showinfo("检验完成", "检验完成！")
        top.destroy()  # 检验完成后关闭子窗口

    # 创建按钮
    select_button = tk.Button(top, text="选择文件或文件夹", command=select_file_or_folder)
    select_button.pack(pady=10)

    validate_button = tk.Button(top, text="开始检验", command=start_validation)
    validate_button.pack(pady=10)

# 预测模型的方法
def predict_model():
    # 创建子窗口
    top = Toplevel()
    top.title("预测模型")
    top.geometry("300x200")
    top.resizable(False, False)

    # 定义变量来存储选择的文件或文件夹
    selected_file = tk.StringVar()

    # 选择文件夹或文件（图片、视频）
    def select_file_or_folder():
        # 弹出选择框，让用户选择文件夹或文件
        file_type = simpledialog.askstring("选择类型", "请输入选择文件夹还是文件（文件夹/文件）：").lower()

        if file_type == "文件":
            # 选择文件（图片或视频）
            selected = filedialog.askopenfilename(
                title="选择文件",
                filetypes=[("所有文件", "*.*"),
                          ("图片文件", "*.jpg;*.png;*.jpeg"),
                          ("视频文件", "*.mp4;*.avi;*.mkv")]
            )
            if selected:
                selected_file.set(selected)
                print(f"选择的文件: {selected}")
            else:
                messagebox.showerror("错误", "未选择任何文件。")
        elif file_type == "文件夹":
            # 选择文件夹
            selected = filedialog.askdirectory(title="选择文件夹")
            if selected:
                selected_file.set(selected)
                print(f"选择的文件夹: {selected}")
            else:
                messagebox.showerror("错误", "未选择任何文件夹。")
        else:
            messagebox.showerror("错误", "选择类型无效，请输入文件夹或文件。")

    def prediction_model_pt(file):
        model = YOLO('best.pt')  # 加载自定义的训练模型
        results = model.predict(
            r"" + file,
            save=True,
            conf=0.5,
            device=0,
            project='runs/predict',  # 输出路径
            iou=0.5)

    # TODO ->开始预测按钮
    def start_prediction():
        file = selected_file.get()
        if not file:
            messagebox.showerror("错误", "请先选择文件或文件夹。")
            return
        # 模拟预测过程
        prediction_model_pt(file)
        messagebox.showinfo("预测完成", "预测完成！")
        top.destroy()  # 预测完成后关闭子窗口

    # 创建按钮
    select_button = tk.Button(top, text="选择文件或文件夹", command=select_file_or_folder)
    select_button.pack(pady=10)

    predict_button = tk.Button(top, text="开始预测", command=start_prediction)
    predict_button.pack(pady=10)

# 开发说明的方法
def show_info():
    # 创建子窗口
    top = Toplevel()
    top.title("开发说明")
    top.geometry("400x400")
    top.resizable(False, False)

    # 创建标题和描述
    title_font = ("Arial", 12, "bold")
    desc_font = ("Arial", 10)

    # YOLOv1 标题和说明
    yolo_label = tk.Label(top, text="YOLO11：目标检测算法", font=title_font)
    yolo_label.pack(pady=5, anchor="w", padx=10)
    yolo_desc = tk.Label(top, text="YOLO（You Only Look Once）是一种实时的目标检测算法，\n"
                                   "能够同时进行分类和定位，适用于高效、快速的目标检测任务。",
                         font=desc_font, wraplength=350)
    yolo_desc.pack(pady=5, padx=20)

    # labelImg 标题和说明
    labelimg_label = tk.Label(top, text="labelImg: 目标检测数据标注工具", font=title_font)
    labelimg_label.pack(pady=5, anchor="w", padx=10)
    labelimg_desc = tk.Label(top, text="labelImg 是一个用 Python 和 Qt 开发的图形化标注工具，\n"
                                      "它可以帮助我们快速地标注图片上的目标，生成用于训练的数据集。",
                             font=desc_font, wraplength=350)
    labelimg_desc.pack(pady=5, padx=20)

    # 致谢标题和说明
    thanks_label = tk.Label(top, text="致谢：感谢‘清华与腾讯的联合实验室’开源的数据集", font=title_font)
    thanks_label.pack(pady=5, anchor="w", padx=10)
    thanks_desc = tk.Label(top, text="感谢‘清华与腾讯的联合实验室’组织或开发者提供开源的数据集，让我们的模型得以训练。\n"
                                     "我们深感荣幸，并会在研究中进行充分的引用。",
                           font=desc_font, wraplength=350)
    thanks_desc.pack(pady=5, padx=20)

    # 关闭按钮
    close_button = tk.Button(top, text="关闭", command=top.destroy)
    close_button.pack(pady=10)

# 创建主窗口
root = tk.Tk()
root.title("基于深度学习的交通标识检验与分类研究")
root.geometry("1000x800")  # 设置固定的窗口大小
root.resizable(False, False)  # 允许调整窗口大小

# 创建左侧标题框架
left_frame = tk.Frame(root)
left_frame.pack(side="left", padx=20, pady=10, fill="y")

# 添加各个标题和描述
train_label = tk.Label(left_frame, text="训练模型：", font=("Arial", 12, "bold"))
train_label.grid(row=0, sticky="w", padx=10)
train_desc = tk.Label(left_frame, text="用于训练机器学习模型，根据数据进行学习。", wraplength=300)
train_desc.grid(row=1, sticky="w", padx=10, pady=5)

validate_label = tk.Label(left_frame, text="校验模型：", font=("Arial", 12, "bold"))
validate_label.grid(row=2, sticky="w", padx=10)
validate_desc = tk.Label(left_frame, text="用于校验模型的准确性和性能，评估模型效果。", wraplength=300)
validate_desc.grid(row=3, sticky="w", padx=10, pady=5)

predict_label = tk.Label(left_frame, text="预测模型：", font=("Arial", 12, "bold"))
predict_label.grid(row=4, sticky="w", padx=10)
predict_desc = tk.Label(left_frame, text="用于通过训练好的模型对新数据进行预测。", wraplength=300)
predict_desc.grid(row=5, sticky="w", padx=10, pady=5)

info_label = tk.Label(left_frame, text="开发说明：", font=("Arial", 12, "bold"))
info_label.grid(row=6, sticky="w", padx=10)
info_desc = tk.Label(left_frame, text="致谢说明", wraplength=300)
info_desc.grid(row=7, sticky="w", padx=10, pady=5)

# 创建右侧按钮框架
button_frame = tk.Frame(root)
button_frame.pack(side="right", padx=20, pady=10, fill="y")

# 创建按钮
train_button = tk.Button(button_frame, text="训练模型", command=train_model)
train_button.pack(pady=5)

validate_button = tk.Button(button_frame, text="校验模型", command=validate_model)
validate_button.pack(pady=5)

predict_button = tk.Button(button_frame, text="预测模型", command=predict_model)
predict_button.pack(pady=5)

info_button = tk.Button(button_frame, text="致谢说明", command=show_info)
info_button.pack(pady=5)

# --- 图片部分 ---

# 创建底部框架，用于存放图片区域
bottom_frame = tk.Frame(root)
bottom_frame.pack(side="bottom", fill="x", padx=10, pady=10)

# --- 图片展示部分 ---

# 添加图片轮播部分
bottom_frame_images = tk.Frame(bottom_frame)
bottom_frame_images.pack(side="left", padx=0, pady=10)  # 图片左侧无间距

# 添加图片轮播标题
image_title = tk.Label(bottom_frame_images, text="图片展示", font=("Arial", 16, "bold"))
image_title.pack(pady=10)

# 图片路径
image_folder = "images"  # 请将你的图片文件夹路径放在此处
image_files = [f for f in os.listdir(image_folder) if f.endswith(('jpg', 'png', 'jpeg'))]
image_files.sort()  # 对图片文件进行排序

# 初始化图片
image_label = tk.Label(bottom_frame_images)
image_label.pack()

# 图片索引
image_index = 0

def show_image():
    global image_index

    # 加载图片
    image_path = os.path.join(image_folder, image_files[image_index])
    img = Image.open(image_path)
    img = img.resize((450, 300))  # 调整图片大小以适应界面
    img_tk = ImageTk.PhotoImage(img)

    # 显示图片
    image_label.config(image=img_tk)
    image_label.image = img_tk

    # 切换到下一张图片
    image_index = (image_index + 1) % len(image_files)

    # 每隔3秒切换一次图片
    root.after(3000, show_image)

# 开始图片轮播
show_image()

# 运行主循环
root.mainloop()
